package com.partner.boot.utils;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.resource.ResourceUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.db.Db;
import cn.hutool.db.DbUtil;
import cn.hutool.db.Entity;
import cn.hutool.db.ds.simple.SimpleDataSource;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import com.baomidou.mybatisplus.generator.fill.Column;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
import org.springframework.core.io.ClassPathResource;

import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.*;

/**
 * 代码生成器
 * v1.0
 * 作者：程序员青戈
 */
@Slf4j
public class CodeGenerator {

    private static final String TABLE = "attractions";
    private static final String PACKAGE_NAME = "com.partner.boot";
    private static final String AUTHOR = "菜牙买菜";
    private static final String VUE_CODE_PATH = "E:\\个人项目\\2022年\\partner交友项目\\资料\\partner-manager\\src\\views\\";

    /*=========================  下面的不用改动  =========================*/

    private static final String PROJECT_PATH = System.getProperty("user.dir");
    public static final String MAPPER_XML_PATH = "/src/main/resources/mapper/";
    public static final String JAVA_CODE_PATH = "/src/main/java/";
    private static final String SPACE8 = "        ";
    private static final boolean lowerEntity = true; // 小写驼峰字符串
    private static final boolean upperEntity = false; // 大写驼峰字符串

    public static void main(String[] args) {
        generateJava(TABLE);

//        generateVueTemplate(TABLE);
    }

    /**
     * Vue代码生成
     *
     * @param tableName
     */
    private static void generateVueTemplate(String tableName) {
        List<TableColumn> tableColumns = getTableColumns(tableName);
        // 读取模板，生成代码
        String vueTemplate = ResourceUtil.readUtf8Str("templates/vue.template");

        Map<String, String> map = new HashMap<>();
        map.put("lowerEntity", disposeEntity(tableName, lowerEntity)); // 接口前缀
        map.put("tableBody", getVueTableBody(tableColumns)); // 模板里的表格信息主体
        map.put("formBody", getVueFormBody(tableColumns));// 模板里的form表单主体
        String vuePage = StrUtil.format(vueTemplate, map); // vuePage：完成替换后的最终模板
        // 写文件
        FileUtil.writeUtf8String(vuePage, VUE_CODE_PATH + disposeEntity(tableName, upperEntity) + ".vue");
        log.debug("==========================" + disposeEntity(tableName, upperEntity) + ".vue文件生成完成！！！==========================");
    }

    /**
     * 要处理的字段信息，如没有注释的字段，设置字段注释，以及不想展示的字段
     *
     * @param tableColumn
     * @return
     */
    private static boolean disposeTableColumn(TableColumn tableColumn) {
        // 如果字段名称为id，且该字段注射为空，则手动设置注释
        if (tableColumn.getColumnName().equalsIgnoreCase("id") && StrUtil.isBlank(tableColumn.getColumnName())) {
            tableColumn.setColumnComment("编号");
        }
        // 不想包含的字段信息，直接略过
        return !tableColumn.getColumnName().equalsIgnoreCase("create_time")
                && !tableColumn.getColumnName().equalsIgnoreCase("update_time")
                && !tableColumn.getColumnName().equalsIgnoreCase("deleted");
    };

    /**
     * 根据字段信息，处理出form表单字符串
     *
     * @param tableColumns
     * @return form表单模板
     */
    private static String getVueFormBody(List<TableColumn> tableColumns) {
        // 拼接字符串
        StringBuilder builder = new StringBuilder();
        for (TableColumn tableColumn : tableColumns) {
            if (disposeTableColumn(tableColumn)) {
                String column = SPACE8 + "<el-form-item prop=\"" + tableColumn.getColumnName() +
                        "\" label=\"" + tableColumn.getColumnComment() + "\" >\n" +
                        SPACE8 + "  <el-input v-model=\"state.form." + tableColumn.getColumnName() + "\" autocomplete=\"off\" />\n" +
                        SPACE8 + "</el-form-item>\n";
                builder.append(column);
            }
        }
        StringBuilder res = builder.replace(builder.lastIndexOf("\n"), builder.length(), ""); // 把最后的换行去掉
        return res.toString();
    };

    /**
     * 通过循坏遍历表格字段信息，将模板字符串里的指定信息进行替换
     *
     * @param tableColumns
     * @return 返回替换后的表格信息主体
     */
    private static String getVueTableBody(List<TableColumn> tableColumns) {
        // 拼接字符串
        StringBuilder builder = new StringBuilder();
        // 遍历表格信息
        for (TableColumn tableColumn : tableColumns) {
            if (disposeTableColumn(tableColumn)) {
                // 进行替换
                String column = SPACE8 + "<el-table-column prop=\"" + tableColumn.getColumnName() + "\" label=\""
                        + tableColumn.getColumnComment() + "\"></el-table-column>\n";
                builder.append(column);
            }
        }
        StringBuilder res = builder.replace(builder.lastIndexOf("\n"), builder.length(), ""); // 把最后的换行去掉
        return res.toString();
    }

    /**
     * 处理表名：小写表的实体名称（sys_user --> user  \  user_rel ---> userRel）
     * 去除指定开头字符串、下划线转驼峰
     * @param tableName 表名称
     * @param isCase true：首字母小写的驼峰字符串 false：首字母大写的驼峰字符串
     * @return
     */
    private static String disposeEntity(String tableName, boolean isCase) {
        tableName = tableName.replaceAll("sys_", "").replaceAll("t_", "");
        if (isCase) {
            return StrUtil.toCamelCase(tableName);
        } else {
            String str = tableName.substring(0, 1).toUpperCase() + tableName.substring(1);
            return StrUtil.toCamelCase(str);
        }
    }

    /**
     * 获取数据库对应表的信息（字段名、字段类型、注释）
     *
     * @param tableName
     * @return 字段数组
     */
    private static List<TableColumn> getTableColumns(String tableName) {
        // 获取数据库连接信息
        DBProp dbProp = getDBProp();
        DataSource dataSource = new SimpleDataSource("jdbc:mysql://localhost:3306/information_schema",
                dbProp.getUsername(), dbProp.getPassword());
        Db db = DbUtil.use(dataSource);

        // 数据库连接地址
        String url = dbProp.getUrl();
        // 要查询的数据库名称
        String schema = url.substring(url.indexOf("3306/") + 5, url.indexOf("?"));
        // 存放数据库表字段数组
        List<TableColumn> tableColumns = new ArrayList<>();
        try {
            List<Entity> columns = db.findAll(Entity.create("COLUMNS").set("TABLE_SCHEMA", schema).set("TABLE_NAME", tableName));
            // 处理需要的字段信息
            for (Entity entity : columns) {
                String columnName = entity.getStr("COLUMN_NAME"); // 字段名称
                String dataType = entity.getStr("DATA_TYPE"); // 字段类型
                String columnComment = entity.getStr("COLUMN_COMMENT"); // 字段注释
                TableColumn column = TableColumn.builder().columnName(columnName).dataType(dataType).columnComment(columnComment).build();
                tableColumns.add(column);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return tableColumns;
    }

    /**
     * 封装获取连接数据库信息的方法
     *
     * @return DBProp类
     */
    private static DBProp getDBProp() {
        ClassPathResource resource = new ClassPathResource("application.yml");
        YamlPropertiesFactoryBean yamlPropertiesFactoryBean = new YamlPropertiesFactoryBean();
        yamlPropertiesFactoryBean.setResources(resource);
        Properties properties = yamlPropertiesFactoryBean.getObject();
        return DBProp.builder().url(properties.getProperty("spring.datasource.url"))
                .username(properties.getProperty("spring.datasource.username"))
                .password(properties.getProperty("spring.datasource.password")).build();
    }

    private static void generateJava(String tableName) {
        DBProp dbProp = getDBProp();
        FastAutoGenerator.create(dbProp.getUrl(), dbProp.getUsername(), dbProp.getPassword())
                .globalConfig(builder -> {
                    builder.author(AUTHOR) // 设置作者
                            .enableSwagger()
                            .disableOpenDir()
                            .outputDir(PROJECT_PATH + JAVA_CODE_PATH); // 指定输出目录
                })
                .packageConfig(builder -> {
                    builder.parent(PACKAGE_NAME) // 设置父包名
                            .moduleName("") // 设置父包模块名
                            .pathInfo(Collections.singletonMap(OutputFile.xml, PROJECT_PATH + MAPPER_XML_PATH)); // 设置mapperXml生成路径
                })
                .strategyConfig(builder -> {
                    builder.controllerBuilder().fileOverride().enableRestStyle().enableHyphenStyle()
                            .serviceBuilder().fileOverride()
                            .mapperBuilder().fileOverride()
                            .entityBuilder().fileOverride().enableLombok()
                            .logicDeleteColumnName("deleted")
                            .addTableFills(new Column("create_time", FieldFill.INSERT))
                            .addTableFills(new Column("update_time", FieldFill.INSERT_UPDATE));
                    builder.addInclude(tableName) // 设置需要生成的表名
                            .addTablePrefix("t_", "sys_"); // 设置过滤表前缀
                })
                .templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板，默认的是Velocity引擎模板
                .execute();
    }

}
